{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "f51b952e-8799-4696-93e2-266cd1041225",
   "metadata": {},
   "source": [
    "# Python 类与面向对象编程（OOP）详解\n",
    "\n",
    "## 课程目标\n",
    "\n",
    "- 深入理解面向对象编程（OOP）的核心概念\n",
    "- 掌握 Python 中类的定义、属性、方法、继承、封装、多态等特性\n",
    "- 学习如何使用 Python 类实现模块化、可重用的代码\n",
    "- 通过示例和练习，熟练运用 OOP 思想解决实际问题\n",
    "\n",
    "---\n",
    "\n",
    "## 1. 面向对象编程（OOP）简介\n",
    "\n",
    "### 1.1 什么是面向对象编程？\n",
    "\n",
    "面向对象编程（OOP）是一种以“对象”为核心的编程范式。对象是数据的集合（称为属性）和相关操作（称为方法）的封装。OOP 通过将现实世界中的实体抽象为代码中的对象，使程序设计更加自然和直观。\n",
    "\n",
    "### 1.2 OOP 的核心概念\n",
    "\n",
    "- **类（Class）**：对象的模板，定义了对象的属性和方法。\n",
    "- **对象（Object）**：类的实例，拥有类中定义的属性和方法。\n",
    "- **封装（Encapsulation）**：将数据和操作捆绑在一起，并限制外部对内部数据的直接访问。\n",
    "- **继承（Inheritance）**：允许子类从父类继承属性和方法，并可扩展或重写。\n",
    "- **多态（Polymorphism）**：不同类的对象对同一方法调用可以表现出不同的行为。\n",
    "- **抽象（Abstraction）**：隐藏复杂性，仅向用户展示必要的接口。\n",
    "\n",
    "### 1.3 OOP 的优势\n",
    "\n",
    "- **模块化**：将代码分解为独立的部分，便于管理和维护。\n",
    "- **可重用性**：通过继承和多态复用代码，减少重复工作。\n",
    "- **可扩展性**：方便在现有基础上添加新功能。\n",
    "- **直观性**：将问题映射到现实世界中的对象，易于理解。\n",
    "\n",
    "---\n",
    "\n",
    "## 2. Python 中的类\n",
    "\n",
    "### 2.1 类的定义\n",
    "\n",
    "- **语法**：\n",
    "\n",
    "  ```python\n",
    "  class 类名:\n",
    "      # 属性（类变量和实例变量）\n",
    "      # 方法（构造函数、实例方法、类方法、静态方法）\n",
    "  ```\n",
    "\n",
    "- **讲解**：\n",
    "\n",
    "  - 使用 `class` 关键字定义类。\n",
    "  - 类名通常采用驼峰命名法（如 `MyClass`）。\n",
    "  - 类内部可以定义属性（存储数据）和方法（描述行为）。\n",
    "\n",
    "#### 示例代码"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "8c867e4e-77f5-4782-be09-01a83171fa11",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "小白 在叫！\n"
     ]
    }
   ],
   "source": [
    "class Dog:\n",
    "    def __init__(self, name, age):\n",
    "        self.name = name  # 实例变量\n",
    "        self.age = age\n",
    "\n",
    "    def bark(self):\n",
    "        print(f\"{self.name} 在叫！\")\n",
    "\n",
    "# 创建对象（实例）\n",
    "my_dog = Dog(\"小白\", 3)\n",
    "my_dog.bark()  # 输出: 小白 在叫！"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "103e7c25-06d9-46c5-a3d6-6f77012cb35d",
   "metadata": {},
   "source": [
    "- **注释**：\n",
    "  - `__init__` 是构造函数，用于初始化对象的属性。\n",
    "  - `self` 代表当前实例，用于访问实例变量和方法。\n",
    "  - `bark` 是实例方法，定义了对象的行为。\n",
    "\n",
    "### 2.2 对象（实例）\n",
    "\n",
    "- **定义**：对象是类的具体实例，每个对象拥有自己的属性和方法。\n",
    "- **讲解**：通过类名加括号调用构造函数创建对象，并传入参数。\n",
    "\n",
    "#### 课堂练习\n",
    "\n",
    "1. 定义一个 `Person` 类，具有 `name` 和 `age` 属性，以及一个 `introduce` 方法，打印自我介绍（如 \"我是 [name]，今年 [age] 岁\"）。\n",
    "2. 创建两个 `Person` 对象并调用它们的 `introduce` 方法。\n",
    "\n",
    "---\n",
    "\n",
    "## 3. 属性\n",
    "\n",
    "属性是类中用于存储数据的变量，分为**实例变量**和**类变量**。\n",
    "\n",
    "### 3.1 实例变量\n",
    "\n",
    "- **定义**：属于对象的变量，每个对象有独立的副本。\n",
    "- **讲解**：在 `__init__` 方法中通过 `self.变量名` 定义。\n",
    "\n",
    "#### 示例代码"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "cb872a2d-e6d8-4792-af0d-8386943b93dc",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Tesla\n",
      "red\n"
     ]
    }
   ],
   "source": [
    "class Car:\n",
    "    def __init__(self, brand, color):\n",
    "        self.brand = brand  # 实例变量\n",
    "        self.color = color\n",
    "\n",
    "my_car = Car(\"Tesla\", \"red\")\n",
    "print(my_car.brand)  # 输出: Tesla\n",
    "print(my_car.color)  # 输出: red"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "7a4a65e0-1c5c-4662-851a-f8be42e45cad",
   "metadata": {},
   "source": [
    "### 3.2 类变量\n",
    "\n",
    "- **定义**：属于类的变量，所有对象共享同一份数据。\n",
    "- **讲解**：在类内部、方法外部定义，通过 `类名.变量名` 访问。\n",
    "\n",
    "#### 示例代码"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "e4c7d592-0418-4f94-870f-dcddadeaadce",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "78.5\n"
     ]
    }
   ],
   "source": [
    "class Circle:\n",
    "    pi = 3.14  # 类变量\n",
    "\n",
    "    def __init__(self, radius):\n",
    "        self.radius = radius  # 实例变量\n",
    "\n",
    "    def area(self):\n",
    "        return Circle.pi * self.radius ** 2\n",
    "\n",
    "c = Circle(5)\n",
    "print(c.area())  # 输出: 78.5"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "3f8f8d72-083c-455c-941f-f256cb5f48f9",
   "metadata": {},
   "source": [
    "- **注释**：\n",
    "  - `pi` 是类变量，所有 `Circle` 对象共享。\n",
    "  - 在方法中通过 `Circle.pi` 访问类变量。\n",
    "\n",
    "#### 课堂练习\n",
    "\n",
    "1. 定义一个 `BankAccount` 类，具有类变量 `interest_rate`（利率，初始值为 0.05），实例变量 `balance`（余额），以及一个 `add_interest` 方法，增加余额的利息（`balance = balance * (1 + interest_rate)`）。\n",
    "\n",
    "---\n",
    "\n",
    "## 4. 方法\n",
    "\n",
    "方法是类中定义的函数，描述对象的行为。Python 中有三种常见方法：**实例方法**、**类方法**和**静态方法**。\n",
    "\n",
    "### 4.1 实例方法\n",
    "\n",
    "- **定义**：操作实例变量的方法，第一个参数是 `self`。\n",
    "- **讲解**：通过对象调用，`self` 指向当前实例。\n",
    "\n",
    "#### 示例代码"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "id": "e97805f1-ce8d-4910-becc-b34ece57aaa1",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Alice 正在学习 数学\n"
     ]
    }
   ],
   "source": [
    "class Student:\n",
    "    def __init__(self, name):\n",
    "        self.name = name\n",
    "\n",
    "    def study(self, subject):\n",
    "        print(f\"{self.name} 正在学习 {subject}\")\n",
    "\n",
    "s = Student(\"Alice\")\n",
    "s.study(\"数学\")  # 输出: Alice 正在学习 数学"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "aafbb0c4-3181-420e-9085-126a7c5ee14a",
   "metadata": {},
   "source": [
    "### 4.2 类方法\n",
    "\n",
    "- **定义**：操作类变量的方法，第一个参数是 `cls`，使用 `@classmethod` 装饰器。\n",
    "- **讲解**：通过类或对象调用，`cls` 指向类本身。\n",
    "\n",
    "#### 示例代码"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "id": "cb15f9c6-7da2-420b-93c3-c0841d797d1b",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "['cheese', 'pepperoni']\n"
     ]
    }
   ],
   "source": [
    "class Pizza:\n",
    "    toppings = [\"cheese\"]  # 类变量\n",
    "\n",
    "    @classmethod\n",
    "    def add_topping(cls, topping):\n",
    "        cls.toppings.append(topping)\n",
    "\n",
    "Pizza.add_topping(\"pepperoni\")\n",
    "print(Pizza.toppings)  # 输出: ['cheese', 'pepperoni']"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4a5dcd13-fc32-4189-9893-0e9715d9d164",
   "metadata": {},
   "source": [
    "- **注释**：\n",
    "  - `add_topping` 是类方法，修改类变量 `toppings`。\n",
    "\n",
    "### 4.3 静态方法\n",
    "\n",
    "- **定义**：与类和实例无关的方法，不需要 `self` 或 `cls`，使用 `@staticmethod` 装饰器。\n",
    "- **讲解**：通常用于工具函数，通过类或对象调用。\n",
    "\n",
    "#### 示例代码"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "id": "e5f8768f-1c17-4613-8c90-4ab376594c2a",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "7\n"
     ]
    }
   ],
   "source": [
    "class MathUtil:\n",
    "    @staticmethod\n",
    "    def add(a, b):\n",
    "        return a + b\n",
    "\n",
    "print(MathUtil.add(3, 4))  # 输出: 7"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d7191fb5-dfdd-45e7-95a8-b589a355db36",
   "metadata": {},
   "source": [
    "#### 课堂练习\n",
    "\n",
    "1. 在 `BankAccount` 类中，添加一个类方法 `set_interest_rate`，用于修改利率。\n",
    "2. 添加一个静态方法 `is_valid_account_number`，接收一个字符串参数，返回是否为有效账号（例如，长度为 10 且全为数字）。\n",
    "\n",
    "---\n",
    "\n",
    "## 5. 封装（Encapsulation）\n",
    "\n",
    "### 5.1 基本概念\n",
    "\n",
    "- **定义**：封装是将数据和操作捆绑在一起，并限制外部对内部数据的直接访问。\n",
    "- **实现方式**：通过私有属性（以 `__` 开头）和公共方法控制访问。\n",
    "- **优点**：隐藏实现细节，保护数据安全。\n",
    "\n",
    "#### 示例代码"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "id": "7a48a3e1-8d21-4e10-ac2f-a4808091b4ec",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1300\n"
     ]
    }
   ],
   "source": [
    "class BankAccount:\n",
    "    def __init__(self, balance):\n",
    "        self.__balance = balance  # 私有属性\n",
    "\n",
    "    def deposit(self, amount):\n",
    "        if amount > 0:\n",
    "            self.__balance += amount\n",
    "\n",
    "    def withdraw(self, amount):\n",
    "        if 0 < amount <= self.__balance:\n",
    "            self.__balance -= amount\n",
    "\n",
    "    def get_balance(self):\n",
    "        return self.__balance\n",
    "\n",
    "account = BankAccount(1000)\n",
    "account.deposit(500)\n",
    "account.withdraw(200)\n",
    "print(account.get_balance())  # 输出: 1300\n",
    "# print(account.__balance)  # AttributeError"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e44ca48f-585b-4192-95ac-59fc0962bda5",
   "metadata": {},
   "source": [
    "- **注释**：\n",
    "  - `__balance` 是私有属性，不能直接访问。\n",
    "  - 通过公共方法 `deposit`、`withdraw` 和 `get_balance` 访问和修改。\n",
    "\n",
    "### 5.2 Getter 和 Setter 方法\n",
    "\n",
    "- **作用**：提供对私有属性的受控访问。\n",
    "- **讲解**：通常用于验证数据或执行额外操作。\n",
    "\n",
    "#### 示例代码"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "id": "d97b91bd-9a86-4c8a-ad8f-80efa619dae5",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "30\n",
      "年龄必须是正数\n"
     ]
    }
   ],
   "source": [
    "class Person:\n",
    "    def __init__(self, name, age):\n",
    "        self.__name = name\n",
    "        self.__age = age\n",
    "\n",
    "    def get_age(self):\n",
    "        return self.__age\n",
    "\n",
    "    def set_age(self, age):\n",
    "        if age > 0:\n",
    "            self.__age = age\n",
    "        else:\n",
    "            print(\"年龄必须是正数\")\n",
    "\n",
    "p = Person(\"Bob\", 25)\n",
    "p.set_age(30)\n",
    "print(p.get_age())  # 输出: 30\n",
    "p.set_age(-5)  # 输出: 年龄必须是正数"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b9100f6e-646e-4958-9bb0-51bcf9f02202",
   "metadata": {},
   "source": [
    "#### 课堂练习\n",
    "\n",
    "1. 在 `Person` 类中，将 `name` 设置为私有属性，提供 `get_name` 和 `set_name` 方法（`set_name` 需检查输入是否为非空字符串）。\n",
    "\n",
    "---\n",
    "\n",
    "## 6. 继承（Inheritance）\n",
    "\n",
    "### 6.1 基本概念\n",
    "\n",
    "- **定义**：子类继承父类的属性和方法，并可扩展或重写。\n",
    "\n",
    "- **语法**：\n",
    "\n",
    "  ```python\n",
    "  class 子类(父类):\n",
    "      # 子类定义\n",
    "  ```\n",
    "\n",
    "- **讲解**：\n",
    "\n",
    "  - 子类可以访问父类的公共属性和方法。\n",
    "  - 子类可以重写父类方法或添加新方法。\n",
    "\n",
    "#### 示例代码"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "id": "aab4793b-7e86-4309-ada7-bf4bdb28d7b3",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "小白 在汪汪叫\n"
     ]
    }
   ],
   "source": [
    "class Animal:\n",
    "    def __init__(self, name):\n",
    "        self.name = name\n",
    "\n",
    "    def speak(self):\n",
    "        print(\"动物在叫\")\n",
    "\n",
    "class Dog(Animal):\n",
    "    def speak(self):\n",
    "        print(f\"{self.name} 在汪汪叫\")\n",
    "\n",
    "dog = Dog(\"小白\")\n",
    "dog.speak()  # 输出: 小白 在汪汪叫"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "96a613ff-6be0-48a8-96d1-491fbfb7b7e0",
   "metadata": {},
   "source": [
    "- **注释**：\n",
    "  - `Dog` 继承 `Animal`，重写 `speak` 方法。\n",
    "  - 调用 `dog.speak()` 时，执行子类的方法。\n",
    "\n",
    "### 6.2 `super()` 函数\n",
    "\n",
    "- **作用**：调用父类的方法。\n",
    "- **讲解**：常用于子类构造函数中调用父类构造函数。\n",
    "\n",
    "#### 示例代码"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "id": "79238b31-c109-4334-96d7-0b8bc93ae752",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "小花 white\n"
     ]
    }
   ],
   "source": [
    "class Cat(Animal):\n",
    "    def __init__(self, name, color):\n",
    "        super().__init__(name)  # 调用父类构造函数\n",
    "        self.color = color\n",
    "\n",
    "cat = Cat(\"小花\", \"white\")\n",
    "print(cat.name, cat.color)  # 输出: 小花 white"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "cbb62615-fe38-475f-8b75-63eb0efed309",
   "metadata": {},
   "source": [
    "### 6.3 多重继承\n",
    "\n",
    "- **定义**：一个子类可以继承多个父类。\n",
    "- **讲解**：Python 支持多重继承，但需注意方法解析顺序（MRO）。\n",
    "\n",
    "#### 示例代码"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "id": "36fe5bbe-77e6-43b2-b4ff-31b69b5042f7",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "A 的方法\n"
     ]
    }
   ],
   "source": [
    "class A:\n",
    "    def method(self):\n",
    "        print(\"A 的方法\")\n",
    "\n",
    "class B:\n",
    "    def method(self):\n",
    "        print(\"B 的方法\")\n",
    "\n",
    "class C(A, B):\n",
    "    pass\n",
    "\n",
    "c = C()\n",
    "c.method()  # 输出: A 的方法"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e1a4657c-cb78-4d64-bca0-685eadcde22c",
   "metadata": {},
   "source": [
    "- **注释**：\n",
    "  - `C` 继承 `A` 和 `B`，调用 `method` 时优先使用 `A` 的方法（根据 MRO）。\n",
    "\n",
    "#### 课堂练习\n",
    "\n",
    "1. 定义一个 `Vehicle` 类，具有 `speed` 属性和 `move` 方法（打印 \"车辆在移动\"）。\n",
    "2. 创建子类 `Car` 和 `Bicycle`，分别重写 `move` 方法（例如，\"汽车以 [speed] km/h 行驶\" 和 \"自行车以 [speed] km/h 骑行\"）。\n",
    "3. 尝试定义一个类 `ElectricCar`，继承 `Car` 并添加 `battery_capacity` 属性。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "32316e39-cab8-4373-aa47-dac7028c5703",
   "metadata": {},
   "source": [
    "## 7. 多态（Polymorphism）\n",
    "\n",
    "### 7.1 基本概念\n",
    "\n",
    "- **定义**：不同类的对象对同一方法调用可以表现出不同的行为。\n",
    "- **实现方式**：通过继承和方法重写实现。\n",
    "\n",
    "#### 示例代码"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 39,
   "id": "c7422d70-28b9-45a2-aead-bf3f278b21bc",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "鸟在飞\n",
      "企鹅不会飞\n"
     ]
    }
   ],
   "source": [
    "class Bird:\n",
    "    def fly(self):\n",
    "        print(\"鸟在飞\")\n",
    "\n",
    "class Penguin(Bird):\n",
    "    def fly(self):\n",
    "        print(\"企鹅不会飞\")\n",
    "\n",
    "def make_fly(animal):\n",
    "    animal.fly()\n",
    "\n",
    "b = Bird()\n",
    "p = Penguin()\n",
    "make_fly(b)  # 输出: 鸟在飞\n",
    "make_fly(p)  # 输出: 企鹅不会飞"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "410a78ef-2246-4a87-9f24-4fd74ff20559",
   "metadata": {},
   "source": [
    "- **注释**：\n",
    "  - `make_fly` 函数接受不同类型的对象，调用它们的 `fly` 方法，表现出多态性。\n",
    "\n",
    "### 7.2 鸭子类型（Duck Typing）\n",
    "\n",
    "- **定义**：Python 强调“如果它走路像鸭子，叫声像鸭子，那么它就是鸭子”，即关注对象的行为而非类型。\n",
    "- **讲解**：多态不仅限于继承，任何实现相同方法的对象都可以互换使用。\n",
    "\n",
    "#### 示例代码"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 42,
   "id": "5b0060c4-3d59-432b-9d87-f104f63fc869",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "嘎嘎\n",
      "人在模仿鸭叫\n"
     ]
    }
   ],
   "source": [
    "class Duck:\n",
    "    def quack(self):\n",
    "        print(\"嘎嘎\")\n",
    "\n",
    "class Person:\n",
    "    def quack(self):\n",
    "        print(\"人在模仿鸭叫\")\n",
    "\n",
    "def make_quack(obj):\n",
    "    obj.quack()\n",
    "\n",
    "d = Duck()\n",
    "p = Person()\n",
    "make_quack(d)  # 输出: 嘎嘎\n",
    "make_quack(p)  # 输出: 人在模仿鸭叫"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b147a4eb-aae3-4696-a337-a1f89b2034e2",
   "metadata": {},
   "source": [
    "- **注释**：\n",
    "  - `Duck` 和 `Person` 不是继承关系，但都实现了 `quack` 方法，因此可以互换使用。\n",
    "\n",
    "#### 课堂练习\n",
    "\n",
    "1. 定义一个 `Shape` 类，具有 `area` 方法（返回 0）。\n",
    "2. 创建子类 `Rectangle`（长 × 宽）和 `Circle`（π × 半径²），重写 `area` 方法。\n",
    "3. 编写一个函数 `print_area`，接收一个 `Shape` 对象并打印其面积。\n",
    "\n",
    "---\n",
    "\n",
    "## 8. 抽象（Abstraction）\n",
    "\n",
    "### 8.1 基本概念\n",
    "\n",
    "- **定义**：抽象是隐藏复杂性，仅向用户展示必要的接口。\n",
    "- **实现方式**：通过抽象类或简单接口。\n",
    "\n",
    "### 8.2 抽象基类（ABC）\n",
    "\n",
    "- **定义**：Python 中使用 `abc` 模块定义抽象基类，强制子类实现某些方法。\n",
    "\n",
    "- **语法**：\n",
    "\n",
    "  ```python\n",
    "  from abc import ABC, abstractmethod\n",
    "  \n",
    "  class AbstractClass(ABC):\n",
    "      @abstractmethod\n",
    "      def method(self):\n",
    "          pass\n",
    "  ```\n",
    "\n",
    "#### 示例代码"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 46,
   "id": "e43cd61e-dc62-46f0-88e2-ee328d2a3294",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "78.5\n"
     ]
    }
   ],
   "source": [
    "from abc import ABC, abstractmethod\n",
    "\n",
    "class Shape(ABC):\n",
    "    @abstractmethod\n",
    "    def area(self):\n",
    "        pass\n",
    "\n",
    "class Circle(Shape):\n",
    "    def __init__(self, radius):\n",
    "        self.radius = radius\n",
    "\n",
    "    def area(self):\n",
    "        return 3.14 * self.radius ** 2\n",
    "\n",
    "# s = Shape()  # TypeError: Can't instantiate abstract class\n",
    "c = Circle(5)\n",
    "print(c.area())  # 输出: 78.5"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "3791d160-56f6-44d5-b315-dfb59d804e50",
   "metadata": {},
   "source": [
    "- **注释**：\n",
    "  - `Shape` 是抽象基类，不能直接实例化。\n",
    "  - 子类 `Circle` 必须实现 `area` 方法。\n",
    "\n",
    "#### 课堂练习\n",
    "\n",
    "1. 定义一个抽象基类 `Employee`，具有抽象方法 `calculate_salary`。\n",
    "2. 创建子类 `FullTimeEmployee` 和 `PartTimeEmployee`，分别实现 `calculate_salary`（例如，全职员工月薪，兼职员工按小时计酬）。\n",
    "\n",
    "---\n",
    "\n",
    "## 9. 重载（Overloading）\n",
    "\n",
    "### 9.1 基本概念\n",
    "\n",
    "- **定义**：在 Python 中，函数或方法可以根据传入参数的不同执行不同操作。\n",
    "- **讲解**：\n",
    "  - Python 不支持传统意义上的方法重载（即同名方法不同参数列表）。\n",
    "  - 可以通过默认参数、可变参数或类型检查实现类似功能。\n",
    "\n",
    "#### 示例代码"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 49,
   "id": "7eae6f24-4906-4623-aba9-71628b0e612a",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1\n",
      "3\n",
      "6\n"
     ]
    }
   ],
   "source": [
    "class Calculator:\n",
    "    def add(self, a, b=0, c=0):\n",
    "        return a + b + c\n",
    "\n",
    "calc = Calculator()\n",
    "print(calc.add(1))       # 输出: 1 (a=1, b=0, c=0)\n",
    "print(calc.add(1, 2))    # 输出: 3 (a=1, b=2, c=0)\n",
    "print(calc.add(1, 2, 3)) # 输出: 6 (a=1, b=2, c=3)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "1107bbab-d83b-4c9f-967a-f763697508a5",
   "metadata": {},
   "source": [
    "- 注释**：\n",
    "  - 通过默认参数实现类似重载的效果。\n",
    "\n",
    "### 9.2 运算符重载\n",
    "\n",
    "- **定义**：通过特殊方法（如 `__add__`）定义类对象对运算符的行为。\n",
    "- **讲解**：使类对象支持 `+`、`-` 等运算符。\n",
    "\n",
    "#### 示例代码"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 52,
   "id": "1d7354b1-e10f-497d-8c0f-2d2c1262e211",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(4, 6)\n"
     ]
    }
   ],
   "source": [
    "class Vector:\n",
    "    def __init__(self, x, y):\n",
    "        self.x = x\n",
    "        self.y = y\n",
    "\n",
    "    def __add__(self, other):\n",
    "        return Vector(self.x + other.x, self.y + other.y)\n",
    "\n",
    "    def __str__(self):\n",
    "        return f\"({self.x}, {self.y})\"\n",
    "\n",
    "v1 = Vector(1, 2)\n",
    "v2 = Vector(3, 4)\n",
    "v3 = v1 + v2\n",
    "print(v3)  # 输出: (4, 6)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "605dec0b-386c-4d91-9d9f-ca5fcce3062c",
   "metadata": {},
   "source": [
    "#### 课堂练习\n",
    "\n",
    "1. 定义一个 `concat` 函数，接收任意数量的字符串并连接它们（使用 `*args`）。\n",
    "2. 为 `Vector` 类添加 `__sub__` 方法，支持向量减法。\n",
    "\n",
    "---\n",
    "\n",
    "## 10. 特殊方法（魔术方法）\n",
    "\n",
    "### 10.1 基本概念\n",
    "\n",
    "- **定义**：以双下划线 `__` 开头和结尾的方法，用于实现类的特殊行为。\n",
    "- **常见特殊方法**：\n",
    "  - `__init__`：构造函数\n",
    "  - `__str__`：返回对象的字符串表示\n",
    "  - `__repr__`：返回对象的官方字符串表示\n",
    "  - `__eq__`：比较两个对象是否相等\n",
    "  - `__len__`：返回对象的长度\n",
    "\n",
    "#### 示例代码 1：`__str__` 和 `__repr__`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 55,
   "id": "6b0aa0d0-6535-46b2-b3c3-ad960cd981f6",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Python 101 by John Doe\n",
      "Book('Python 101', 'John Doe')\n"
     ]
    }
   ],
   "source": [
    "class Book:\n",
    "    def __init__(self, title, author):\n",
    "        self.title = title\n",
    "        self.author = author\n",
    "\n",
    "    def __str__(self):\n",
    "        return f\"{self.title} by {self.author}\"\n",
    "\n",
    "    def __repr__(self):\n",
    "        return f\"Book('{self.title}', '{self.author}')\"\n",
    "\n",
    "b = Book(\"Python 101\", \"John Doe\")\n",
    "print(str(b))  # 输出: Python 101 by John Doe\n",
    "print(repr(b))  # 输出: Book('Python 101', 'John Doe')"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "5d91828e-fbb6-4225-a788-107cf57fff2d",
   "metadata": {},
   "source": [
    "示例代码 2：`__eq__`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 58,
   "id": "833d41c8-8e28-490d-8b40-521447f40147",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "True\n",
      "False\n"
     ]
    }
   ],
   "source": [
    "class Person:\n",
    "    def __init__(self, name, age):\n",
    "        self.name = name\n",
    "        self.age = age\n",
    "\n",
    "    def __eq__(self, other):\n",
    "        return self.name == other.name and self.age == other.age\n",
    "\n",
    "p1 = Person(\"Alice\", 25)\n",
    "p2 = Person(\"Alice\", 25)\n",
    "p3 = Person(\"Bob\", 30)\n",
    "print(p1 == p2)  # 输出: True\n",
    "print(p1 == p3)  # 输出: False"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "7910f8af-6eda-4d4d-94f9-43259c2b9105",
   "metadata": {},
   "source": [
    "#### 课堂练习\n",
    "\n",
    "1. 为 `Person` 类添加 `__len__` 方法，返回名字的长度。\n",
    "2. 为 `BankAccount` 类添加 `__eq__` 方法，比较两个账户的余额是否相等。\n",
    "\n",
    "---\n",
    "\n",
    "## 11. 综合练习\n",
    "\n",
    "### 练习 1：图书馆系统\n",
    "\n",
    "- 定义 `Book` 类，具有 `title`、`author` 和 `isbn` 属性。\n",
    "- 定义 `Library` 类，具有 `books` 列表（初始为空），方法：\n",
    "  - `add_book`：添加书籍\n",
    "  - `remove_book`：移除书籍（根据 `isbn`）\n",
    "  - `find_book_by_title`：根据标题查找书籍并返回。\n",
    "\n",
    "### 练习 2：银行系统\n",
    "\n",
    "- 定义 `BankAccount` 类，具有私有属性 `__balance`，方法 `deposit`、`withdraw`（检查余额是否足够）和 `get_balance`。\n",
    "- 定义子类 `SavingsAccount`，增加 `interest_rate` 属性和 `add_interest` 方法。\n",
    "\n",
    "### 练习 3：图形计算\n",
    "\n",
    "- 定义 `Shape` 类，具有 `area` 和 `perimeter` 方法（返回 0）。\n",
    "- 创建子类 `Rectangle` 和 `Circle`，重写 `area` 和 `perimeter` 方法。\n",
    "- 编写函数 `print_shape_info`，接收 `Shape` 对象并打印其面积和周长。\n",
    "\n",
    "---\n",
    "\n",
    "## 12. 课程总结\n",
    "\n",
    "- **类**：对象的蓝图，定义属性和方法。\n",
    "- **属性**：\n",
    "  - 实例变量：每个对象独立拥有。\n",
    "  - 类变量：所有对象共享。\n",
    "- **方法**：\n",
    "  - 实例方法：操作实例变量。\n",
    "  - 类方法：操作类变量。\n",
    "  - 静态方法：独立工具函数。\n",
    "- **封装**：隐藏内部实现，提供接口访问。\n",
    "- **继承**：子类复用和扩展父类。\n",
    "- **多态**：统一接口，不同实现。\n",
    "- **抽象**：隐藏复杂性，强制实现。\n",
    "- **重载**：通过参数实现灵活性。\n",
    "- **特殊方法**：定制类的行为。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "4b4d41e6-2623-4be0-97a7-a692bee3c460",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python [conda env:base] *",
   "language": "python",
   "name": "conda-base-py"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.12.2"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
